#include "ref.h"
#include "xkit.h"

// 
Reference *RefInit(losu_vm_t vm) {
    Reference *out = __xkit_malloc(sizeof(Reference));
    losu_object ulock = obj_newunit(vm, obj_unittype_unit);
    out->ulock = ulock;
    vm_lock(vm, &(ulock));
    return out;
}

void RefFree(losu_vm_t vm, Reference *ref) {
    vm_unlock(vm, &(ref->ulock));
    __xkit_free(ref);
}

void __increase(losu_vm_t vm, losu_object ulock, losu_object *cur) {
    losu_object_t value = obj_unitindex(vm, ulock, *cur);
    if (value) {
        obj_unitset(vm, ulock, *cur, obj_newnum(vm, obj_getnum(vm, value) + 1));
    } else {
        obj_unitset(vm, ulock, *cur, obj_newnum(vm, 1));
    }
}

// increase
void RefIncrease(losu_vm_t vm, Reference *ref, losu_object *o, size_t olen) {
    losu_object ulock = ref->ulock;
    for (size_t i = 0; i < olen; i ++) {
        losu_object_t cur = o + i;
        switch (cur->type) {
            case losu_object_type_false:
            case losu_object_type_true:
            case losu_object_type_number:
            case losu_object_type_pointer: {
                break;
            }
            // need lock
            case losu_object_type_string:
            case losu_object_type_coroutine:
            case losu_object_type_function:
            case losu_object_type_unit: {
                __increase(vm, ulock, cur);
                break;
            }
            default: {
                vm_error(vm, "xkit error: Increase error");
            }
        }
    }
}

void __decrease(losu_vm_t vm, losu_object ulock, losu_object *cur) {
    losu_object_t value = obj_unitindex(vm, ulock, *cur);
    if (value) {
        double n = obj_getnum(vm, value);
        if (n == 1) {
            const losu_object ofalse = obj_newfalse(vm);
            obj_unitset(vm, ulock, *cur, ofalse);
        } else {
            const losu_object on = obj_newnum(vm, n - 1);
            obj_unitset(vm, ulock, *cur, on);
        }
    } else {
        vm_error(vm, "xkit error: Decrease error");
    }
}

// decrease
void RefDecrease(losu_vm_t vm, Reference *ref, losu_object *o, size_t olen) {
    for (size_t i = 0; i < olen; i ++) {
        losu_object_t cur = o + i;
        switch (cur->type) {
            case losu_object_type_false:
            case losu_object_type_true:
            case losu_object_type_number:
            case losu_object_type_pointer: {
                break;
            }
            // need lock
            case losu_object_type_string:
            case losu_object_type_coroutine:
            case losu_object_type_function:
            case losu_object_type_unit: {
                __decrease(vm, ref->ulock, cur);
                break;
            }
            default: {
                vm_error(vm, "xkit error: Decrease error");
            }
        }
    }
}
